
"""产品的改造"""

from odoo import models, api, fields
from odoo.tools import float_compare
from odoo.exceptions import UserError, ValidationError


def set_default_invoice_policy(field_default):
    """将产品的开票策略一律改成交货/收到数量"""
    field_default['invoice_policy'] = 'delivery'
    field_default['purchase_method'] = 'receive'
    if 'type' not in field_default:
        field_default['type'] = 'product'


class ProductImage(models.Model):
    _name = 'nd.product.image'
    _description = '产品图片'

    name = fields.Char('名称')
    image = fields.Binary('图片', attachment=True)
    product_tmpl_id = fields.Many2one('product.template', '关联产品', copy=True)
    partner_id = fields.Many2one('res.partner', '关联合作伙伴', copy=True)


class Product(models.Model):
    _name = 'product.template'
    _inherit = ['product.template', 'gsp.manage.base']

    nd_size = fields.Char('产品规格')

    gsp_management = fields.Boolean('是否需要GSP管理', compute="_compute_gsp_management", states={},
                                    store=True, track_visibility='onchange')
    gsp_type = fields.Selection([('medicine', '药品'), ('instrument', '医疗器械'), ('other', '其他')],
                                   string="用于", readonly=True,
                                   states={'draft': [('readonly', False)]}, track_visibility='onchange')
    expire_manage = fields.Boolean('启用效期管理')
    validity_date = fields.Integer('有效期')
    validity_uom = fields.Selection([('day', '天'), ('month', '月'), ('year', '年')], string="有效期单位")
    # 医疗器械相关
    gsp_categ_id = fields.Many2one('gsp.product.categ', string="产品分类",
                                   readonly=True, states={'draft': [('readonly', False)]}, track_visibility='onchange')
    certificate_num = fields.Many2one('gsp.certificate', string='注册证号或备案凭证号')
    approve_date = fields.Date('批准日期', related="certificate_num.approve_date", store=True)
    expire_date = fields.Date('有效期至', related="certificate_num.expire_date", store=True)
    gsp_manage_type_id = fields.Many2one('gsp.manage.type', string="管理类别")
    producer_id = fields.Many2one('gsp.producer', string="生产厂家")
    gsp_storage_condition_id = fields.Many2one('gsp.storage.condition', string="存储条件")
    is_import_medicine = fields.Boolean('是否进口药品')
    gsp_maintain_type_id = fields.Many2one('gsp.maintain.type', string="GSP养护类别")
    gsp_expire_id = fields.Many2one('gsp.expiring.type', string='GSP近效期类别',readonly=True,
                                    states={'draft': [('readonly', False)]}, track_visibility='onchange')
    quality_standard = fields.Char('质量标准')
    product_permit_code = fields.Char('生产许可证号')
    import_certificate_num = fields.Char('进口药品注册号')
    origin_permit_code = fields.Char('原注册证号')
    produce_place = fields.Char('产地')
    expected_usage = fields.Text('预期用途')
    is_cold_chain_medicine = fields.Boolean('是否冷链药品')
    instrument_categ_id = fields.Many2one('gsp.instrument.categ', string="医疗器械分类",readonly=True,
                                    states={'draft': [('readonly', False)]},)

    # 药品相关
    common_name = fields.Char('通用名称')
    dosage_id = fields.Many2one('gsp.dosage.categ', string="剂型")
    is_anti_virus = fields.Boolean('是否抗生素')
    approve_num = fields.Char('批准文号')
    prescription_type = fields.Selection([
        ('prescript', '处方药'),
        ('otc_a', '甲类OTC'),
        ('otc_b', '乙类OTC')], string="处方分类")

    is_anti_cancer = fields.Boolean('是否抗肿瘤药')
    is_special = fields.Boolean('是否特殊药品')
    is_injectable = fields.Boolean('是否注射药剂')

    # 图片和附件
    nd_imgs = fields.One2many('nd.product.image', 'product_tmpl_id', string='图片')
    nd_files = fields.Many2many('ir.attachment', string='文件', attachment=True)

    # 价格记录
    nd_total_sale_qty = fields.Float('销售总数')
    nd_total_sale_money = fields.Float('销售总金额')
    nd_top_sale_price = fields.Float('最高销售价格')
    nd_low_sale_price = fields.Float('最低销售价格')
    nd_recent_sale_price = fields.Float('最近销售价格')
    nd_avg_sale_price = fields.Float('平均销售价格')

    nd_total_purchase_qty = fields.Float('采购总数')
    nd_total_purchase_money = fields.Float('采购总金额')
    nd_top_purchase_price = fields.Float('最高采购价格')
    nd_low_purchase_price = fields.Float('最低采购价格')
    nd_recent_purchase_price = fields.Float('最近采购价格')
    nd_avg_purchase_price = fields.Float('平均采购价格')

    @api.model
    def default_get(self, fields):
        """将产品的开票策略一律改成交货/收到数量"""
        res = super().default_get(fields)
        set_default_invoice_policy(res)
        return res

    @api.multi
    def write(self, val):
        res= super().write(val)
        return res

    @api.constrains('default_code')
    def _nd_constrains_default_code(self):
        """限制default_code唯一"""
        for product in self:
            if product.default_code:
                same_default_code_products = self.env['product.template'].sudo().search([('default_code', '=', product.default_code)])
                if same_default_code_products - product:
                    raise UserError('“产品编码”属性值不能重复！')

    @api.depends('gsp_categ_id')
    def _compute_gsp_management(self):
        for product in self:
            if product.gsp_categ_id:
                product.gsp_management = product.gsp_categ_id.gsp_management

    @api.model
    def update_nd_sale_price(self, sale_order_lines):
        """
        更新产品价格信息，一般在确认销售单时调用此方法来更新，
        其中，平均单价遍历所有的销售单根据销售数量来平均。其他的几个单价都直接根据传入的明细行更新
        :param sale_order_lines: sale.order.line，确认销售的销售明细
        :return:
        """
        for line in sale_order_lines.filtered(lambda x: x.update_product_price is False):
            product = line.product_id
            try:
                avg_price = (product.nd_total_sale_money + line.price_subtotal) / (product.nd_total_sale_qty + line.product_uom_qty)
            except ZeroDivisionError:
                avg_price = 0
            product.write({
                'nd_top_sale_price': max(product.nd_top_sale_price, line.price_unit),
                'nd_low_sale_price': min(product.nd_low_sale_price, line.price_unit) if product.nd_low_sale_price > 0 else line.price_unit,
                'nd_recent_sale_price': line.price_unit,
                'nd_avg_sale_price': avg_price,
                'nd_total_sale_qty': product.nd_total_sale_qty + line.product_uom_qty,
                'nd_total_sale_money': product.nd_total_sale_money + line.price_subtotal,
            })
            line.update_product_price = True

    @api.model
    def update_nd_purchase_price(self, purchase_order_lines):
        """
        更新产品价格信息，一般在确认采购单时调用此方法来更新，
        其中，平均单价遍历所有的采购单根据采购数量来平均。其他的几个单价都直接根据传入的明细行更新
        :param purchase_order_lines: purchase.order.line，确认采购的采购明细
        :return:
        """
        for line in purchase_order_lines.filtered(lambda x: x.update_product_price is False):
            product = line.product_id

            try:
                avg_price = (product.nd_total_purchase_money + line.price_subtotal) / (product.nd_total_purchase_qty + line.product_qty)
            except ZeroDivisionError:
                avg_price = 0
            product.write({
                'nd_top_purchase_price': max(product.nd_top_purchase_price, line.price_unit),
                'nd_low_purchase_price': min(product.nd_low_purchase_price, line.price_unit) if product.nd_low_purchase_price > 0 else line.price_unit,
                'nd_recent_purchase_price': line.price_unit,
                'nd_avg_purchase_price': avg_price,
                'nd_total_purchase_qty': product.nd_total_purchase_qty + line.product_qty,
                'nd_total_purchase_money': product.nd_total_purchase_money + line.price_subtotal,
            })
            line.update_product_price = True


class ProductProduct(models.Model):
    _inherit = 'product.product'

    @api.model
    def create(self, val):
        code = val['product_tmpl_id']
        default_code = self.env['product.template'].search([('id','=',code)]).default_code
        val['default_code'] = default_code
        res = super().create(val)
        return res

    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        """允许对名称、产品编码、产品规格进行搜索， TODO 抛弃了系统原生功能，可能会出问题"""
        if not args:
            args = []
        args.extend(['|', ('name', 'ilike', name), '|', ('default_code', 'ilike', name), ('nd_size', 'ilike', name)])
        products = self.search(args, limit=limit)
        return products.name_get()

    @api.multi
    def write(self, val):
        res = super().write(val)
        return res

    @api.model
    def default_get(self, fields):
        """将产品的开票策略一律改成交货/收到数量"""
        res = super().default_get(fields)
        set_default_invoice_policy(res)
        return res


